package main

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/astaxie/beedb"
	"github.com/bitly/go-simplejson"
	_ "github.com/go-sql-driver/mysql"
	"os"
	"reflect"
	//"runtime"
	"strconv"
	"time"
)

type mss []map[string]string
type msf []map[string]float32
type mapsu map[string]uint32
type mapsf map[string]float32
type mssf map[string]map[string]float32

//const route = "/usr/local/bin/recommend/"
const route = ""
var databaseName string
func init(){
	file, _ := os.Open(route + "config.json")
	fileInfo, _ := os.Stat(route + "config.json")
	fileSize := fileInfo.Size()
	config := make([]byte, fileSize)
	file.Read(config)
	json, _ := simplejson.NewJson(config)
	databaseName = json.Get("database").MustString()
}
func main() {
	tnow := time.Now().Unix()
	//根据注册时间找出老顾客
	orm, db := GetDblink()
	_ = db
Here:
	a, _ := orm.SetTable("user").SetPK("id").Where("id>?", 0).Select("id, login_name, registry_time").FindMap()
	var userArr mss
	for _, v := range a {
		userArr = append(userArr, map[string]string{"id": string(v["id"]), "login_name": string(v["login_name"]), "registry_time": string(v["registry_time"])})
	}
	//查找注册时间大于一个月的客户
	var comm_person mss
	for _, v := range userArr {
		regi_time, _ := strconv.ParseInt(v["registry_time"], 10, 64)
		if tnow-regi_time > 259200 {
			comm_person = append(comm_person, v)
		}
	}

	//借阅平均值，每人借阅数
	single_borr_num, borrow_aver := getBorrowAver(&comm_person, orm) //map[string]uint32

	//vip_borrow_customer
	vip_borrow_customer := getVipCustomer(comm_person, &single_borr_num, &borrow_aver) //[]map[string]uint32

	//收藏平均值，每人收藏数
	single_coll_num, collect_aver := getCollectAver(&comm_person, orm)

	//vip_collect_customer
	vip_collect_customer := getVipCustomer(comm_person, &single_coll_num, &collect_aver) //[]map[string]uint32

	_ = single_borr_num
	_ = vip_borrow_customer
	_ = vip_collect_customer
	//mss
	//借阅和收藏vip客户合体
	for _, v := range vip_borrow_customer {
		equal_keyNum := 0
		for _, cv := range vip_collect_customer {
			if v["id"] == cv["id"] {
				equal_keyNum += 1
			}
		}
		if equal_keyNum == 0 {
			vip_collect_customer = append(vip_collect_customer, v)
		}
	}
	vip_customer := vip_collect_customer
	_ = vip_customer //[]map[string]string

	max_borrow_num := getMaxNum(vip_customer, single_borr_num)
	max_collect_num := getMaxNum(vip_customer, single_coll_num)
	_ = max_collect_num
	_ = max_borrow_num

	single_borr_rate, single_coll_rate := getFtmRate(single_borr_num, single_coll_num, max_borrow_num, max_collect_num)
	_ = single_coll_rate // 收藏加权值 需要乘以0.5   msf  "uid":"分"
	_ = single_borr_rate // 借阅加权值 需要乘以0.5   msf  "uid":"分"
	// custom_item map[string]map[string]float32
	var vip_key []string
	for _, k := range vip_customer {
		vip_key = append(vip_key, k["id"])
	}
	vip_item := getUserItem(orm, vip_customer, single_borr_rate, single_borr_rate)
	json_vip_item, _ := json.Marshal(vip_item)
	saveJson(json_vip_item, route+"jsonfile/vip_item.json")
	comm_item := getUserItem(orm, comm_person, single_borr_rate, single_borr_rate)
	json_comm_item, _ := json.Marshal(comm_item)
	saveJson(json_comm_item, route+"jsonfile/comm_item.json")
	goto Here
}

//获得数据库连接对象orm
func GetDblink() (beedb.Model, *sql.DB) {
	db, err := sql.Open("mysql", "root:123456@/" + databaseName + "?charset=utf8")
	if err != nil {
		panic(err)
	}
	orm := beedb.New(db)
	return orm, db
}

//借阅平均值
func getBorrowAver(comm_person *mss, db beedb.Model) (map[string]uint32, float32) {
	//var single_borr_num []map[string]uint32
	single_borr_num := make(map[string]uint32)
	var borrow_sum uint32 = 0
	for _, v := range *comm_person {
		result, _ := db.SetTable("borrowrec").SetPK("id").Where("user_id=?", v["id"]).Select("count(*) as num").FindMap() //[]map[string][]byte
		num, _ := strconv.ParseUint(string(result[0]["num"]), 10, 64)
		//single_borr_num = append(single_borr_num, map[string]uint32{v["id"]: uint32(num)})
		single_borr_num[v["id"]] = uint32(num)
		borrow_sum += uint32(num)
		//result []map[string][]uint8
	}
	borrow_aver := float32(borrow_sum) / float32(len(*comm_person))
	return single_borr_num, borrow_aver
}

//求大于等于借阅平均值的客户
func getVipCustomer(comm_person mss, single_borr_num *map[string]uint32, borrow_aver *float32) mss {
	vip_num := make(map[string]uint32)
	for key, val := range *single_borr_num {
		if float32(val) >= *borrow_aver && *borrow_aver != 0 {
			vip_num[key] = val
		}
	}

	var vip_customer mss //下载量vip_customer集合

	for key, _ := range vip_num {
		for ck, cv := range comm_person {
			if key == cv["id"] {
				vip_customer = append(vip_customer, comm_person[ck])
			}
		}
	}
	return vip_customer
}

//收藏平均值
func getCollectAver(comm_person *mss, db beedb.Model) (map[string]uint32, float32) {
	//var single_coll_num []map[string]uint32
	single_coll_num := make(map[string]uint32)
	var collect_sum uint32 = 0
	for _, v := range *comm_person {
		result, _ := db.SetTable("collect").SetPK("id").Where("user_id=?", v["id"]).Select("count(*) as num").FindMap() //[]map[string][]byte
		num, _ := strconv.ParseUint(string(result[0]["num"]), 10, 64)
		//single_coll_num = append(single_coll_num, map[string]uint32{v["id"]: uint32(num)})
		single_coll_num[v["id"]] = uint32(num)
		collect_sum += uint32(num)
		//result []map[string][]uint8
	}
	collect_aver := float32(collect_sum) / float32(len(*comm_person))
	return single_coll_num, collect_aver
}

//得到收藏，借阅最大值
//max_borrow_num, max_collect_num := getMaxNum(vip_customer, single_borr_num, single_coll_num)
func getMaxNum(vip_customer mss, single_num map[string]uint32) uint32 {
	//求vip的 t m 值 t为借阅值 m为收藏值  single_borr_num []map[string]uint32
	var max_num uint32 = 0
	for _, v := range vip_customer {
		for sk, sv := range single_num {
			if v["id"] == sk {
				if max_num < sv {
					max_num = sv
				}
			}
		}
	}
	return max_num
}

/**
 *获取ftm表
 */
//getFtmRate(single_borr_num, single_coll_num, max_borrow_num, max_collect_num)
func getFtmRate(single_borr_num mapsu, single_coll_num mapsu, max_borrow_num uint32, max_collect_num uint32) (mapsf, mapsf) {
	//single_borr_num []map[string]uint32
	single_borr_rate := make(map[string]float32)
	_ = reflect.TypeOf("")
	_ = single_borr_rate
	for key, val := range single_borr_num {
		var rate float32 = 0
		rate = (float32(val) / float32(max_borrow_num)) * 0.5
		single_borr_rate[key] = rate
	}

	single_coll_rate := make(map[string]float32)
	_ = single_borr_rate
	for key, val := range single_coll_num {
		var rate float32 = 0
		rate = (float32(val) / float32(max_collect_num)) * 0.5
		single_coll_rate[key] = rate
	}
	mix_rate := make(mapsf)
	for k, v := range single_borr_rate {
		mix_rate[k] = v + single_coll_rate[k]
	}
	_ = mix_rate //混合加权值
	//添加总的rate
	return single_borr_rate, single_coll_rate
}

//获取物品与人物的阵列
func getUserItem(orm beedb.Model, comm_person mss, single_borr_rate mapsf, single_coll_rate mapsf) map[string]map[string]float32 {
	pendent_borr_item, _ := orm.SetTable("borrowrec").Select("distinct res_id").FindMap()
	book_item, _ := orm.SetTable("borrowrec").Select("distinct res_id, user_id").FindMap()
	pendent_coll_item, _ := orm.SetTable("collect").Select("distinct res_id").FindMap()
	collect_item, _ := orm.SetTable("collect").Select("distinct res_id,user_id").FindMap()
	_ = book_item
	_ = collect_item

	var borr_items mss
	for _, v := range book_item {
		borr_items = append(borr_items, map[string]string{"res_id": string(v["res_id"]), "user_id": string(v["user_id"])})

	}
	var pendent_borr_items mss
	for _, v := range pendent_borr_item {
		pendent_borr_items = append(pendent_borr_items, map[string]string{"res_id": string(v["res_id"])})
	}

	var coll_items mss
	for _, v := range collect_item {
		coll_items = append(coll_items, map[string]string{"res_id": string(v["res_id"]), "user_id": string(v["user_id"])})
	}

	var pendent_coll_items mss
	for _, v := range pendent_coll_item {
		pendent_coll_items = append(pendent_coll_items, map[string]string{"res_id": string(v["res_id"])})
	}

	custom_item := make(map[string]map[string]float32)
	_ = custom_item
	for _, v := range comm_person { //mss
		nei := make(map[string]float32)
		_ = nei
		for _, bv := range pendent_borr_items { //borr_items mss []map[string][string]
			var has int = 0
			var num float32 = 0
			_ = num
			for _, brv := range borr_items {
				if brv["user_id"] == v["id"] && brv["res_id"] == bv["res_id"] {
					has += 1
				}
			}
			if has != 0 {
				num = 1
				nei[bv["res_id"]] = num + single_borr_rate[v["id"]]
			} else {
				nei[bv["res_id"]] = 0
			}
			custom_item[v["id"]] = nei
		}
		_ = custom_item
	}
	for _, v := range comm_person {
		for _, bv := range pendent_coll_items { //borr_items mss []map[string][string]
			var has int = 0
			var num float32 = 0
			_ = num
			for _, brv := range coll_items {
				if brv["user_id"] == v["id"] && brv["res_id"] == bv["res_id"] {
					has += 1
				}
			}
			if has != 0 {
				num = 0.5
				if custom_item[v["id"]][bv["res_id"]] != 0 {
					custom_item[v["id"]][bv["res_id"]] += 0.5 + single_coll_rate[v["id"]]
				} else {
					custom_item[v["id"]][bv["res_id"]] = 0.5 + single_coll_rate[v["id"]]
				}
			} else {
				custom_item[v["id"]][bv["res_id"]] += 0
			}
		}
	}

	return custom_item
}

//保存用户商品评分信息到json
func saveJson(json_custom_item []byte, file_url string) {
	userFile := file_url
	os.Mkdir(route+"jsonfile", 0777)
	fout, _ := os.Create(userFile)
	fout.Write(json_custom_item)
	defer fout.Close()

}
